package com.feri.rbacsys.filter;

import com.alibaba.fastjson.JSON;
import com.feri.rbacsys.security.entity.LoginUser;
import com.feri.rbacsys.util.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;


/**
 * @projectName: springboot2
 * @package: com.feng.filter
 * @className: JwtAuthenticationTokenFilter
 * @author: Ladidol
 * @description: 令牌认证过滤器
 * @date: 2022/4/30 1:18
 * @version: 1.0
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Resource
    StringRedisTemplate template;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // 1.校验当前请求的接口 获取token
        String token = request.getHeader("access_token"); // 前端设置请求头
        // 请求是登录接口，直接放行
        if (request.getRequestURI().contains("erp/api/user/login")) {
            filterChain.doFilter(request, response);
            return;
        }
        // 为null 就放行
        if (token == null) {
            filterChain.doFilter(request, response);
            return;
        } else {
            // 解析令牌
            //校验令牌是否为空
            if (StringUtils.hasLength(token)) {
                //校验令牌是否有效
                if (template.hasKey("ss:auth:" + token)) {
                    //获取 令牌 对应的认证用户
                    String json = template.opsForValue().get("ss:auth:" + token);
                    // 从redis中读取信息
                    LoginUser loginUser = JSON.parseObject(json, LoginUser.class);
                    loginUser.setAuthorities();
                    log.info("认证拦截：" + json);
                    // 需要把认证的用户信息 设置到Spring Security
                    UsernamePasswordAuthenticationToken upToken
                            = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
                    // 存入SecurityContextHolder, 其他filter会通过这个来获取当前用户信息
                    SecurityContextHolder.getContext().setAuthentication(upToken);

                    //刷新令牌的有效期
                    template.expire("ss:auth:" + token, 30, TimeUnit.MINUTES);
                    // 放行
                    filterChain.doFilter(request, response);
                    return;
                } else {
                    throw new UsernameNotFoundException("令牌无效！");
                }
            } else {
                throw new UsernameNotFoundException("令牌是假的！");
            }
        }
    }
}
